package com.demo.service.impl;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.demo.constant.LoginConstant;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class UserServiceDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        String loginType = requestAttributes.getRequest().getParameter("login_type");//区分是后台人员还是用户

        if(StringUtils.isEmpty(loginType)){
            throw new AuthenticationServiceException("登录类型不能为null");
        }
        UserDetails userDetails = null;
        try{
            String grantType = requestAttributes.getRequest().getParameter("grant_type");//获取类型
            if(LoginConstant.REFRESH_TYPE.equals(grantType.toUpperCase())){
                username= adjustUsername(username,loginType);
            }

        switch (loginType){
            case LoginConstant.ADMIN_TYPE :
                userDetails = loadAdminUserByUsername(username);
                break;
            case LoginConstant.MEMBER_TYPE:
                userDetails= loadMemberUserByUsername(username);
                break;
            default:
                throw new AuthenticationServiceException("暂不支持的登录方式");
            }
         }catch(IncorrectResultSizeDataAccessException e){
            throw new UsernameNotFoundException("用户名"+username+"不存在");
        }
        return userDetails;
    }

    /**
     * 纠正用户名称
     * @param username 用户id
     * @param loginType admin_type member_type
     * @return
     */
    private String adjustUsername(String username, String loginType) {
        if(LoginConstant.ADMIN_TYPE.equals(loginType)){
            //管理员纠正方式
            return jdbcTemplate.queryForObject(LoginConstant.QUERY_ADMIN_USER_WITH_ID,String.class,username);
        }
        if(LoginConstant.MEMBER_TYPE.equals(loginType)){
            //用户纠正方式
            return jdbcTemplate.queryForObject(LoginConstant.QUERY_MEMBER_USER_WITH_ID,String.class,username);
        }
        return username;
    }

    /**
     * 后台用户登录
     * @param username
     * @return
     */
    private UserDetails loadAdminUserByUsername(String username) {
        return jdbcTemplate.queryForObject(LoginConstant.QUERY_ADMIN_SQL, new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs, int i) throws SQLException {
                if(rs.wasNull()){
                    throw new UsernameNotFoundException("用户名"+username+"不存在");
                }
                long id = rs.getLong("id");//用户id
                String password = rs.getString("password");//用户密码
                int status = rs.getInt("status");//用户状态
                return new User(String.valueOf(id), password, status == 1, true, true,true,getSysUserPermissions(id));
            }
        },username);
    }

    /**
     * 会员登录
     * @param username
     * @return
     */
    private UserDetails loadMemberUserByUsername(String username) {
        return jdbcTemplate.queryForObject(LoginConstant.QUERY_MEMBER_SQL, new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                if (rs.wasNull()) {
                    throw new UsernameNotFoundException("用户：" + username + "不存在");
                }
                long id = rs.getLong("id");//会员id
                String password = rs.getString("password");//会员密码
                int status = rs.getInt("status");//会员状态
                return new User(
                        String.valueOf(id),
                        password,
                        status == 1,
                        true,
                        true,
                        true,
                        Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))
                );
            }
        },username,username);
        //2.查询这个用户对应权限
        //3.封装成一个UserDetails对象返回
    }

    /**
     * 根据ID查询 用户信息
     * @param id
     * @return
     */
    private Collection<? extends GrantedAuthority> getSysUserPermissions(long id) {
        //1.当用户为超级管理员时,拥有所有权限
        String roleCold=jdbcTemplate.queryForObject(LoginConstant.QUERY_ROLE_CODE_SQL,String.class,id);
        List<String>  permissions = null;
        if(LoginConstant.ADMIN_ROLE_CODE.equals(roleCold)){
            //超级用户
            permissions = jdbcTemplate.queryForList(LoginConstant.QUERY_ALL_PERMISSIONS,String.class);
        }else {
            //2.普通用户,需要使用角色->权限数据
            permissions= jdbcTemplate.queryForList(LoginConstant.QUERY_PERMISSION_SQL,String.class,id);
        }
        if(CollectionUtils.isEmpty(permissions)){
            return Collections.emptySet();
        }else {
            return permissions.stream()
                    .distinct()//去重
                    .map(SimpleGrantedAuthority::new)
                    .collect(Collectors.toSet());
        }

    }
}
